/**
  ******************************************************************************
  * @file    bsp_usart_ex.c
  * @author  Iron
  * @date 	 2018-08-08
  * @version v1.0
  * @brief   bsp_usart_ex c file
  */

/** @addtogroup GROUP_BSP
  * @{
  */

/* includes ------------------------------------------------------------------*/
#include "bsp_usart_ex.h"

/* BEBUG LOG */
#include "debug_log.h"
#define LOG_LOCAL_LEVEL DBG_LOG_DEBUG
DBG_LOG_TAG("BSP_USART_EX");

/* private typedef -----------------------------------------------------------*/
/* private macro -------------------------------------------------------------*/
/* private variables ---------------------------------------------------------*/
/* private function prototypes -----------------------------------------------*/
/* private functions ---------------------------------------------------------*/

static void bsp_usart_rx_indicate_cb(void *handle, uint32_t length)
{
  bsp_usart_handle_t *husart = handle;
  if (husart && husart->evt_handle) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xEventGroupSetBitsFromISR(husart->evt_handle, BSP_USART_RX_EVT, &xHigherPriorityTaskWoken);
    if (husart->rx_indicate) husart->rx_indicate(husart, length, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
  }
}

static void bsp_usart_tx_complete_cb(void *handle)
{
  bsp_usart_handle_t *husart = handle;
  if (husart && husart->evt_handle) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xEventGroupSetBitsFromISR(husart->evt_handle, BSP_USART_TXC_EVT, &xHigherPriorityTaskWoken);
    if (husart->tx_complete) husart->tx_complete(husart, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
  }
}

int32_t bsp_usart_ex_init( bsp_usart_handle_t *husart, bsp_usart_id_t uart, uint32_t baudrate,
                           usart_ex_isr_rx_indicate_t rx_indicate, usart_ex_isr_tx_complete_t tx_complete)
{
  if (uart >= BSP_USART_MAX) {
    return -1;
  }
  husart->uart = uart;
  husart->rx_indicate = rx_indicate;
  husart->tx_complete = tx_complete;
  husart->evt_handle = xEventGroupCreateStatic(&husart->evt);
  if (husart->evt_handle == NULL) {
    DBG_LOGE(TAG, "uart %d event group create error.", uart);
    return -2;
  }

  return bsp_usart_init(husart, uart, baudrate, bsp_usart_rx_indicate_cb, bsp_usart_tx_complete_cb);
}

int32_t bsp_usart_send_ex(bsp_usart_handle_t *husart, uint8_t *data, int32_t len, uint32_t timeout)
{
  int32_t res;

  xEventGroupClearBits(husart->evt_handle, BSP_USART_TXC_EVT);

  res = bsp_usart_dma_tx(husart->uart, data, len);
  if (res == len) {
    EventBits_t bits = xEventGroupWaitBits(husart->evt_handle, BSP_USART_TXC_EVT, pdTRUE, pdTRUE, pdMS_TO_TICKS(timeout));
    if ( bits & BSP_USART_TXC_EVT) {
      return len;
    }
  }

  DBG_LOGE(TAG, "usart %d send timeout.", husart->uart);
  return 0;
}

// The function caller take the responsibility to keep "data" safe!
int32_t bsp_usart_send_tx_no_wait(bsp_usart_handle_t *husart, uint8_t *data, int32_t len)
{
  return bsp_usart_dma_tx(husart->uart, data, len);
}

int32_t bsp_usart_getbyte_ex(bsp_usart_handle_t *husart, uint8_t *data, uint32_t timeout)
{
  int32_t res = 0;

  do {
    res = bsp_usart_rx(husart->uart, data, 1);
    if ( res != 1) {
      EventBits_t bits = xEventGroupWaitBits(husart->evt_handle, BSP_USART_RX_EVT, pdTRUE, pdTRUE, pdMS_TO_TICKS(timeout));
      if(!(bits & BSP_USART_RX_EVT)) break;
    }
  } while(res != 1);

  return res;
}

int32_t bsp_usart_recv_ex(bsp_usart_handle_t *husart, uint8_t *data, int32_t size, uint32_t timeout)
{
  int32_t res, rxlen = 0;

  for (rxlen = 0; rxlen < size; ) {
    res = bsp_usart_rx(husart->uart, &data[rxlen], (size - rxlen));
    if ( res > 0) {
      rxlen += res;
    } else {
      EventBits_t bits = xEventGroupWaitBits(husart->evt_handle, BSP_USART_RX_EVT, pdTRUE, pdTRUE, pdMS_TO_TICKS(timeout));
      if(!(bits & BSP_USART_RX_EVT)) break;
    }
  }

  return rxlen;
}

/**
  * @}
  */

/******************* (C)COPYRIGHT 2018 ***** END OF FILE *********************/
